package org.soarsky.wealthchengdu.tools;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONObject;

import android.util.Log;

/**
 * 解析JSON 包装类
 * 
 * @author
 * @date 2012-12-9 下午9:18:33
 * @version V1.0
 */
public class ParserJsonFactory {
	public static boolean errorLog = false;

	/**
	 * 快速解析必须实现的接口，它只是一个形式不需要方法 一旦实现了该接口，该实体就具备了匹配JSON数据模式 实现该接口对象不能被
	 * 代码混淆，以防止注入值失败
	 * 
	 * @author gaochao
	 * @date 2013-2-26 下午3:29:43
	 * @version V1.0
	 */
	public interface ParserJsonListener {

	}

	/**
	 * 返回信息
	 * 
	 * @author
	 * @date 2013-2-7 上午9:51:58
	 * @version V1.0
	 */
	public static class ResponseCode<T> {
		private int resCode = -1;
		private T resData = null;

		// 是否连接成功
		public boolean connectOk() {
			return resCode == 200;
		}

		// 是否有返回数据
		public boolean haveData() {
			return resCode == 200 && resData != null;
		}

		/**
		 * @return the resCode
		 */
		public int getResCode() {
			return resCode;
		}

		/**
		 * @param resCode
		 *            the resCode to set
		 */
		public void setResCode(int resCode) {
			this.resCode = resCode;
		}

		/**
		 * @return the resData
		 */
		public T getResData() {
			return resData;
		}

		/**
		 * @param resData
		 *            the resData to set
		 */
		public void setResData(T resData) {
			this.resData = resData;
		}

	}

	private static class PaserEment {
		public static final int NODE_DEF = 1;
		// 是否是一个数组用List<T> 存储
		public static final int NODE_LIST = 2;
		// 是否是另一个实体类
		public static final int NODE_EMENT = 3;
		public static final int NODE_ARRAY = 4;
		public int type = NODE_DEF;
		public String ement = null;
		/**
		 * 该字段类型
		 * */
		public Class<?> ementType = null;
		/**
		 * 数组类对象类型
		 * */
		public Class<?> arrayType = null;
	}

	/**
	 * 获取网络字符流
	 * */
	public static <T> ResponseCode<T> parserJsonHead(String url,
			List<NameValuePair> list, Class<T> mode, boolean isPost)
			throws Exception {
		HttpPost httpPostUtil = new HttpPost(url);
		DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
		if (list != null)
			httpPostUtil.setEntity(new UrlEncodedFormEntity(list, HTTP.UTF_8));
		defaultHttpClient.getParams().setParameter(
				CoreConnectionPNames.CONNECTION_TIMEOUT, 5000);
		HttpResponse httpResponse = defaultHttpClient.execute(httpPostUtil);
		ResponseCode<T> responseCode = new ResponseCode<T>();
		responseCode.setResCode(httpResponse.getStatusLine().getStatusCode());
		if (responseCode.getResCode() == 200) {
			String msg = new String(EntityUtils.toByteArray(httpResponse
					.getEntity()));
			if (msg != null) {
				T t = parseAnnotationJsonData(new JSONObject(msg), mode, true);
				responseCode.setResData(t);
			}
		}
		return responseCode;
	}

	/**
	 * 获取网络字符流POST 方式
	 * */
	public static ResponseCode<String> parserJsonHeadPost(String url,
			List<NameValuePair> list) throws Exception {
		HttpPost httpPostUtil = new HttpPost(url);
		DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
		if (list != null)
			httpPostUtil.setEntity(new UrlEncodedFormEntity(list, HTTP.UTF_8));
		defaultHttpClient.getParams().setParameter(
				CoreConnectionPNames.CONNECTION_TIMEOUT, 5000);
		HttpResponse httpResponse = defaultHttpClient.execute(httpPostUtil);
		ResponseCode<String> responseCode = new ResponseCode<String>();
		responseCode.setResCode(httpResponse.getStatusLine().getStatusCode());
		if (responseCode.getResCode() == 200) {
			String msg = EntityUtils.toString(httpResponse.getEntity());
			if (msg != null) {
				responseCode.setResData(msg);
			}
		}
		return responseCode;
	}

	/**
	 * 获取网络字符流GET方式
	 * */
	public static ResponseCode<String> parserJsonHeadGet(String url,
			List<NameValuePair> list) throws Exception {
		StringBuilder sb = null;
		if (list != null && list.size() != 0) {
			boolean isFirst = true;
			sb = new StringBuilder();
			sb.append(url).append("?");
			for (NameValuePair p : list) {
				if (isFirst) {
					isFirst = false;
					sb.append(p.getName());
					sb.append("=");
				} else {
					sb.append("&");
					sb.append(p.getName());
					sb.append("=");
				}
				sb.append(p.getValue());
			}
		}
		if (sb != null)
			url = sb.toString();
		HttpGet httpPostUtil = new HttpGet(url);
		DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
		defaultHttpClient.getParams().setParameter(
				CoreConnectionPNames.CONNECTION_TIMEOUT, 5000);
		HttpResponse httpResponse = defaultHttpClient.execute(httpPostUtil);
		ResponseCode<String> responseCode = new ResponseCode<String>();
		responseCode.setResCode(httpResponse.getStatusLine().getStatusCode());
		if (responseCode.getResCode() == 200) {
			String msg = EntityUtils
					.toString(httpResponse.getEntity(), "utf-8");
			if (msg != null) {
				responseCode.setResData(msg);
			}
		}
		return responseCode;
	}

	// 最大缓存类模型个数默认1000;
	private static int MAX_CACHE_ATTRIBUTE = 1000;

	public static void setMaxCacheAttributeNumber(int max) {
		MAX_CACHE_ATTRIBUTE = max;
	}

	// 存放注入值 属性名信息
	private static LinkedHashMap<String, Hashtable<String, PaserEment>> attributes = new LinkedHashMap<String, Hashtable<String, PaserEment>>() {
		private static final long serialVersionUID = 1L;

		@Override
		protected boolean removeEldestEntry(
				Entry<String, Hashtable<String, PaserEment>> eldest) {
			// TODO Auto-generated method stub
			if (size() > MAX_CACHE_ATTRIBUTE) {
				return true;
			}
			return false;
		}

	};

	/**
	 * @param json
	 *            解析json串
	 * @param data
	 *            解析数据模式实例
	 * @param cache
	 *            是否缓存模信息以便第二次快速读取
	 * @throws Exception
	 */
	public static void parseAnnotationJsonData(JSONObject json, Object data,
			boolean cache) throws Exception {
		if (!(data instanceof ParserJsonListener)) {
			final String msg = data.getClass().getName();
//			throw new RuntimeException(msg + "未能实现ParserJsonListener接口!");
			if(errorLog){
				Log.w("System.out", msg+ " 未能实现ParserJsonListener接口!");
			}
			return;
		}
		final String className = data.getClass().getName();
		Hashtable<String, PaserEment> attribute = cache ? attributes
				.get(className) : getAttribute(data);
		if (attribute == null) {
			attribute = getAttribute(data);
			attributes.put(className, attribute);
		}
		for (Entry<String, PaserEment> entry : attribute.entrySet()) {
			parserType(entry.getKey(), entry.getValue(), json, data, cache);
		}
	}

	/**
	 * @param json
	 *            解析json传
	 * @param data
	 *            要解析的类类型
	 * @param cache
	 *            是否缓存
	 * @return
	 * @throws Exception
	 */
	public static <T> T parseAnnotationJsonData(JSONObject json, Class<T> data,
			boolean cache) throws Exception {
		@SuppressWarnings("unchecked")
		T obj = (T) newDataItem(data);
		parseAnnotationJsonData(json, obj, cache);
		return obj;
	}

	// 分类解析
	@SuppressWarnings("unchecked")
	private static void parserType(String nodeName, PaserEment ement,
			JSONObject json, Object data, boolean cache) throws Exception {
		if (json.isNull(ement.ement)) {
			if (errorLog)
				Log.w("System.out", "在json中没有发现 " + ement.ement + " 字段");
			return;
		}
		Method method = null;
		Object ementData = null;
		switch (ement.type) {
		case PaserEment.NODE_DEF:
			final String values = json.getString(ement.ement);
			if (!LengthUtils.isEmpty(values))
				invokeSet(data, nodeName, values);
			break;
		case PaserEment.NODE_EMENT:// 解析成员类对象
			JSONObject jsonObject = json.getJSONObject(ement.ement);
			method = data.getClass().getMethod("get" + getMethodName(nodeName));
			ementData = method.invoke(data);
			if (ementData == null) {// 判断等于NULL就实例化该对象
				ementData = newDataItem(ement.ementType);
			}
			parseAnnotationJsonData(jsonObject, ementData, cache);
			method = data.getClass().getMethod("set" + getMethodName(nodeName),
					ement.ementType);
			method.invoke(data, ementData);// 设置值
			break;
		case PaserEment.NODE_LIST:
			method = data.getClass().getMethod("get" + getMethodName(nodeName));
			ementData = method.invoke(data);
			if (ementData == null) {// 判断等于NULL就实例化该对象
				ementData = new ArrayList<Object>();
			}
			if (ementData instanceof List) {
				parserList((List<Object>) ementData, ement.arrayType,
						json.getJSONArray(ement.ement), cache);
				method = data.getClass().getMethod(
						"set" + getMethodName(nodeName), ement.ementType);
				method.invoke(data, ementData);// 设置值
			}
			break;
		case PaserEment.NODE_ARRAY:
			method = data.getClass().getMethod("set" + getMethodName(nodeName),
					ement.ementType);
			Object o=parserArray(json.getJSONArray(ement.ement));
			method.invoke(data, o);// 设置值
			break;
		default:
			break;
		}
	}

	/**
	 * @param list
	 *            结果集
	 * @param dataType
	 *            要解析的数据类
	 * @param jsonArray
	 *            json串
	 * @param cache
	 *            是否缓存类结构信息
	 * @throws Exception
	 */
	public static void parserList(List<Object> list, Class<?> dataType,
			JSONArray jsonArray, boolean cache) throws Exception {
		int len = jsonArray.length();
		Object data = null;
		JSONObject json = null;
		for (int i = 0; i < len; i++) {
			data = newDataItem(dataType);
			json = jsonArray.getJSONObject(i);
			if (data instanceof String) {
				data = json.toString();
			} else
				parseAnnotationJsonData(json, data, cache);
			list.add(data);
		}
	}
	//解析String[]数组
	public static String[] parserArray(JSONArray jsonArray) throws Exception {
		int len = jsonArray.length();
		ArrayList<String> list = new ArrayList<String>();
		for (int i = 0; i < len; i++) {
			list.add(jsonArray.getString(i));
		}
		return list.toArray(new String[len]);
	}

	// 获取所有属性名称
	private static Hashtable<String, PaserEment> getAttribute(Object data) {
		// 不允许加密实体类
		Class<?> entityClass = data.getClass();
		Hashtable<String, PaserEment> attribute = new Hashtable<String, PaserEment>();
		Field[] fields = entityClass.getDeclaredFields();
		boolean flag = false;
		Field field = null;
		String nodeName = null;
		PaserEment paserEment = null;
		for (int i = 0; i < fields.length; i++) {
			paserEment = new PaserEment();
			field = fields[i];
			nodeName = field.getName();
			flag = field.isAnnotationPresent(ParserJsonNode.class);// 是否有ParserJsonNode
			if (flag) {
				ParserJsonNode id = (ParserJsonNode) field
						.getAnnotation(ParserJsonNode.class);
				if (!id.isParser())// 不解析该字段
					continue;
				// 如果有解析字段就用解析字段，没有直接用属性解析
				paserEment.ement = id.parseName() != null
						&& id.parseName().length() != 0 ? id.parseName()
						: nodeName;
				paserEment.ementType = field.getType();
				decideType(paserEment, field);
				if (paserEment.type == PaserEment.NODE_LIST) {
					if (paserEment.arrayType == null)
						paserEment.arrayType = id.arrayType();
					if (paserEment.arrayType == null) {
						throw new RuntimeException("List<T>  T未知,请告知泛型");
					}
				}
			} else {
				paserEment.ement = nodeName;
				paserEment.ementType = field.getType();
				decideType(paserEment, field);
				if (paserEment.type == PaserEment.NODE_LIST
						&& paserEment.arrayType == null) {
					throw new RuntimeException("List<T>  T未知,请告知泛型");
				}
			}
			attribute.put(nodeName, paserEment);
		}
		return attribute;
	}

	// 对数据类型进行判断
	private static void decideType(PaserEment paserEment, Field field) {
		final boolean isPrimitive = paserEment.ementType.isPrimitive()
				|| String.class.getName()
						.equals(paserEment.ementType.getName());
		if (isPrimitive) {
			paserEment.type = PaserEment.NODE_DEF;
		} else if (paserEment.ementType.isAssignableFrom(List.class)) {
			paserEment.type = PaserEment.NODE_LIST;
			if (paserEment.arrayType == null) {// 这里获取类的泛型
				Type fc = field.getGenericType();
				if (fc != null && (fc instanceof ParameterizedType)) {// 如果是泛型参数的类型
					ParameterizedType pt = (ParameterizedType) fc;
					final Class<?> genericClazz = (Class<?>) pt
							.getActualTypeArguments()[0]; // 得到泛型里的class类型对象。
					paserEment.arrayType = genericClazz;
				}
			}
		} else if (paserEment.ementType.isArray()) {
			if(String.class.equals(paserEment.ementType.getComponentType())){
				paserEment.type = PaserEment.NODE_ARRAY;
				paserEment.arrayType = String.class;
			}else{
				if (errorLog)
					Log.w("System.out", "数组类型只支持String[]!");
			}
		} else {
			paserEment.type = PaserEment.NODE_EMENT;
		}
	}

	// 把一个字符串的第一个字母大写、效率是最高的、
	public static String getMethodName(String fildeName) throws Exception {
		final byte[] items = fildeName.getBytes();
		items[0] = (byte) ((char) items[0] - 'a' + 'A');
		return new String(items);
	}

	// new出该对象
	private static Object newDataItem(Class<?> c) throws Exception {
		return c.getConstructor().newInstance();
	}

	// 这里指支持String 和一般基本类型 的注入
	public static void invokeSet(Object o, String fieldName, String value) {
		try {
			if (o == null)
				return;
			Class<?> objectClass = o.getClass();
			Field field = objectClass.getDeclaredField(fieldName);
			final Object buf = convert(field, value);
			if (buf == null)
				return;
			// fieldName = "set" + fieldName.substring(0, 1).toUpperCase()
			// + fieldName.substring(1);
			fieldName = "set" + getMethodName(fieldName);
			Method method = objectClass.getMethod(fieldName, field.getType());
			method.invoke(o, buf);
		} catch (Exception e) {
			if (errorLog)
				System.out.println(e.toString());
		}
	}

	// 注入String[]数组
	public static void invokeSet(Object o, String fieldName, Object array) {
		try {
			if (o == null)
				return;
			Class<?> objectClass = o.getClass();
			Field field = objectClass.getDeclaredField(fieldName);
			// fieldName = "set" + fieldName.substring(0, 1).toUpperCase()
			// + fieldName.substring(1);
			fieldName = "set" + getMethodName(fieldName);
			Method method = objectClass.getMethod(fieldName, field.getType());
			method.invoke(o, array);
		} catch (Exception e) {
		}
	}

	private static Object convert(Field field, String value) {
		final Object genericType = field.getGenericType();
		final String type = genericType.toString();
		Object buf = null;
		if (type.equals("int")) {
			buf = Integer.valueOf(value);
		} else if (type.equals("long")) {
			buf = Long.valueOf(value);
		} else if (type.equals("double")) {
			buf = Double.valueOf(value);
		} else if (type.equals("float")) {
			buf = Float.valueOf(value);
		} else if (type.equals("short")) {
			buf = Short.valueOf(value);
		} else if (type.equals("byte")) {
			buf = Byte.valueOf(value);
		} else if (type.equals("boolean")) {
			buf = Boolean.valueOf(value);
		} else if (type.equals(String.class.toString())) {
			buf = value;
		} else {
			if (errorLog)
				System.out.println("没有匹配的类型!!");
			buf = null;
		}
		return buf;
	}

}
